package ru.susu.algebra.centralunits.alternating.tex.local;

import java.math.BigInteger;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import ru.susu.algebra.centralunits.alternating.MathMethodWithInitializers;
import ru.susu.algebra.centralunits.alternating.initializers.ExponentsInitializer;
import ru.susu.algebra.centralunits.alternating.initializers.QuadraticFieldsInitializer;
import ru.susu.algebra.centralunits.alternating.initializers.SpecialRowsInitializer;
import ru.susu.algebra.chartable.constructor.AlternatingCharTableUtil;
import ru.susu.algebra.field.quadratic.QuadraticField;
import ru.susu.algebra.jtex.ITexElement;
import ru.susu.algebra.jtex.ITexSubItemsElement;
import ru.susu.algebra.jtex.SimpleTexElementWithCode;
import ru.susu.algebra.jtex.StringTexElement;
import ru.susu.algebra.jtex.TexBeginEndElement;
import ru.susu.algebra.jtex.UnionTexElement;
import ru.susu.algebra.jtex.formula.FormulaTexElement;
import ru.susu.algebra.jtex.formula.GreekSymbols;
import ru.susu.algebra.jtex.formula.MathSymbols;
import ru.susu.algebra.jtex.utils.TexUtils;
import ru.susu.algebra.pair.Pair;
import ru.susu.algebra.partition.Partition;
import ru.susu.algebra.properties.IPropertySource;
import ru.susu.algebra.util.CollectionUtils;
import ru.susu.algebra.util.NumberUtilities;

/**
 * @author akargapolov
 * @since: 10.09.2010
 */
public class ExponentsLemma extends MathMethodWithInitializers<ITexElement>
{
	private static final Class[] DEPENDENCIES = {SpecialRowsInitializer.class,  QuadraticFieldsInitializer.class, ExponentsInitializer.class};


/*	\begin{lemma}\label{exp}
	Пусть $l=\exp(\Un(\Z[\omega]/z\Z[\omega]))$ --- показатель группы
	единиц $\exp(\Un(\Z[\omega]/z\Z[\omega]))$ фактор--кольца
	$\Z[\omega]/z\Z[\omega]$. Тогда
	\begin{gather}
	l_{20}=43680,для z_{20}=z(\chi_{20})=2^6\cdot3^2\cdot5^2\cdot7^2\cdot13=9172800\\
	l_{57}=55440,для z_{57}=z(\chi_{57})=2^2\cdot3^3\cdot5^2\cdot7^2\cdot11=1455300\\
	l_{59}=30240,для z_{59}=z(\chi_{59})=2^6\cdot3^4\cdot5\cdot7^2=1270080
	\end{gather}
	\end{lemma}*/
	private String getLemmaStatement(IPropertySource ps, Partition partition) throws Exception
	{
		String index = TexUtils.index(SpecialRowsInitializer.getRowNumber(ps, partition));
		BigInteger lcm = ExponentsInitializer.getLcmExponent4Partition(ps, partition);
		BigInteger z = AlternatingCharTableUtil.calcZX(partition);
		return "l" + index + " = " + lcm + ", для z" + index + " = z" + TexUtils.inBrackets(GreekSymbols.CHI + index) + " = " + TexUtils.getFactorization(z) + " = " + z;
	}

	private ITexSubItemsElement getLemma(IPropertySource ps) throws Exception
	{
		ITexSubItemsElement lemma = TexBeginEndElement.lemma().addSubElement(SimpleTexElementWithCode.label("exp"));
		String zOmega = "\\Z[" + GreekSymbols.OMEGA + "]/z\\Z[" + GreekSymbols.OMEGA + "]";
		String exp = MathSymbols.EXP + TexUtils.inBrackets("\\Un" + TexUtils.inBrackets(zOmega));
		lemma.addSubElement(StringTexElement.text(
				"Пусть $l=" + exp + "$ --- показатель группы\n" +
				"единиц $" + exp + "$ фактор--кольца\n" +
				"$" + zOmega + "$. Тогда\n"));
		TexBeginEndElement gather = TexBeginEndElement.gather();
		StringBuffer buffer = new StringBuffer();
		for (Partition partition : SpecialRowsInitializer.listSpecialNotIntegerCharacterRows(ps))
		{
			buffer = buffer.length() == 0 ? buffer.append("") : buffer.append(MathSymbols.DOUBLE_INV_SLASH + "\n");
			buffer.append(getLemmaStatement(ps, partition));
		}
		return lemma.addSubElement(gather.addSubElement(StringTexElement.text(buffer.toString())));
	}

	private ITexElement getExponentsElement(IPropertySource ps, Partition partition) throws Exception
	{
		String index = TexUtils.index(SpecialRowsInitializer.getRowNumber(ps, partition));
		BigInteger lcm = ExponentsInitializer.getLcmExponent4Partition(ps, partition);
		BigInteger z = AlternatingCharTableUtil.calcZX(partition);
		Map<Integer, Integer> map = NumberUtilities.factorization2Map(z);
		BigInteger d = QuadraticFieldsInitializer.getOmega(ps, partition).getD();
		String sqrtD = TexUtils.inBrackets(FormulaTexElement.sqrt(d));
		String omegaIndex = GreekSymbols.OMEGA + TexUtils.index(d);
		QuadraticField quadraticField = AlternatingCharTableUtil.getQuadraticField4SpecialRow(partition);
		String generalUnit = TexUtils.toTexString(quadraticField.getGeneralUnit());

		UnionTexElement union = UnionTexElement.union();
		union.addSubElement(StringTexElement.text(
				"Теперь по предложению 5 из \\cite{Aleev3} имеем"));

	/*	\begin{gather}
		\exp(\Un(\Z[\omega]/P^{6e_2})=3\cdot2^5=96,\\
		\exp(\Un(\Z[\omega]/T^{2e_3})=2\cdot3^1=6,\\
		\exp(\Un(\Z[\omega]/F^{2e_5})=4\cdot5=20,\\
		\exp(\Un(\Z[\omega]/S^{2e_7})=6\cdot7=42,\\
		\exp(\Un(\Z[\omega]/E^{2e_13})=12\cdot13=156.
		\end{gather} */
		StringBuffer buffer = new StringBuffer();
		List<Pair<Integer, BigInteger>> exponents4Partition = ExponentsInitializer.getExponents4Partition(ps, partition);
		for (Pair<Integer, BigInteger> pair : exponents4Partition)
		{
			buffer = buffer.length() == 0 ? buffer : buffer.append(",\\\\ \n");
			Integer prime = pair.getKey();
			Integer pow = map.get(prime);
			BigInteger exp = pair.getValue();
			buffer.append(getExp(Pair.pair(prime, pow)) + " = " + TexUtils.getFactorization(exp) + " = " + exp);
		}
		buffer.append(".");
		ITexElement gather = TexBeginEndElement.gather().addSubElement(StringTexElement.text(buffer.toString()));
		union.addSubElement(gather);

	/*	Отсюда $l_{20}=\text{ НОК
		}(96,6,20,42,156)=2^5\cdot3\cdot5\cdot7\cdot13=43680$, где
		$\Q(\chi_{20})=\Q(\sqrt{13})$, кольцо целых поля $\Q(\sqrt{13})$
		равно $\Z[\omega]$, где $\omega_{13}=\frac{1+\sqrt{13}}{2}$ и группа
		единиц
		\[
		\Un(\Z[\omega])=\langle-1\rangle\times\langle1+\omega_{13}\rangle
		\] */
		Collection<BigInteger> exponents = CollectionUtils.getValues(exponents4Partition);
		union.addSubElement(StringTexElement.text(
				"Отсюда $l" + index + " = " + SimpleTexElementWithCode.text(" НОК ") + MathSymbols.LEFT_BRACKET +
				CollectionUtils.toString(exponents, ",") + MathSymbols.RIGHT_BRACKET + " = " + TexUtils.getFactorization(lcm) + " = " + lcm + "$, где\n" +
				"$\\Q" + TexUtils.inBrackets(GreekSymbols.CHI + index) + " = \\Q" + sqrtD + "$, кольцо целых поля $\\Q" + sqrtD + "$\n" +
				"равно $\\Z[" + GreekSymbols.OMEGA + "]$, где $" + omegaIndex + " = " + FormulaTexElement.frac("1 + " + FormulaTexElement.sqrt(d), "2") + "$ и группа единиц \n" +
				"\\[\n" +
				"\\Un" + TexUtils.inBrackets("\\Z[" + GreekSymbols.OMEGA + "]") + " = " + FormulaTexElement.LANGLE + " - 1" + FormulaTexElement.RANGLE + FormulaTexElement.TIMES +
				FormulaTexElement.LANGLE + generalUnit + FormulaTexElement.RANGLE + "\n" +
				"\\]\n"));

	/*	\begin{equation}
		 \lambda=\varepsilon(1+\omega_{13})^k,
		\end{equation}
		где $\varepsilon\in\{1,-1\}$ и $k\in\Z$.*/
		union.addSubElement(TexBeginEndElement.equation().addSubElement(
				StringTexElement.text(GreekSymbols.LAMBDA + "=" + FormulaTexElement.VAREPSILON + "\\left(" + generalUnit + "\\right)^k,")));
		union.addSubElement(StringTexElement.text("где $" + FormulaTexElement.VAREPSILON + FormulaTexElement.IN + "\\{1,-1\\}$ и $k\\in\\Z$."));
		return union;
	}

/*	$P$ --- простой идеал из $\Z[\omega]$, содержащий $2$, и $e_2$
	--- его индекс ветвления над $2\Z$,
	 $T$ --- простой идеал из $\Z[\omega]$, содержащий $3$, и $e_3$
	--- его индекс ветвления над $3\Z$, $F$ --- простой идеал из $\Z[\omega]$,
	содержащий $5$, и $e_5$ --- его индекс ветвления над $5\Z$, $S$
	--- простой идеал из $\Z[\omega]$, содержащий $7$, и $e_7$
	--- его индекс ветвления над $7\Z$, $E$
	--- простой идеал из $\Z[\omega]$, содержащий $13$, и $e_{13}$
	--- его индекс ветвления над $13\Z$. */
	private ITexElement getIndexesElement(IPropertySource ps, Partition partition) throws Exception
	{
		BigInteger z = AlternatingCharTableUtil.calcZX(partition);

		StringBuffer buffer = new StringBuffer();
		for (Pair<Integer, Integer> pair : NumberUtilities.factorization(z))
		{
			Integer key = pair.getKey();
			buffer = buffer.length() == 0 ? buffer : buffer.append(",\n");
			buffer.append("$P" + TexUtils.index(key) + "$ --- простой идеал из $\\Z[" + GreekSymbols.OMEGA + "]$, ")
					.append("содержащий $" + key + "$, и $e" +TexUtils.index(key) + "$ --- его индекс ветвления над $" + key + "\\Z$");
		}
		return StringTexElement.text(buffer.append(".\n").toString());
	}

	/**
	 * \exp(\Un(\Z[\omega]/P^{6e_2})
	 */
	private String getExp(Pair<Integer, Integer> pair)
	{
		return MathSymbols.EXP + TexUtils.inBrackets("\\Un" + TexUtils.inBrackets("\\Z[" + GreekSymbols.OMEGA + "]/P" + TexUtils.index(pair.getKey()) +
				TexUtils.pow(NumberUtilities.toString(BigInteger.valueOf(pair.getValue()), false, false) + "e" + TexUtils.index(pair.getKey()))));
	}
/*	Так как $z_{20}=9172800=2^6\cdot3^2\cdot5^2\cdot7^2\cdot13$, то по
	лемме 3 из \cite{Aleev2} $l_{20}$ --- наименьшее общее кратное чисел
	\[
	\exp(\Un(\Z[\omega]/P^{6e_2}),\ \exp(\Un(\Z[\omega]/T^{2e_3}),\
	\exp(\Un(\Z[\omega]/F^{2e_5})\, \exp(\Un(\Z[\omega]/S^{2e_7})\text{
	и }\exp(\Un(\Z[\omega]/E^{2e_{13}}),
	\]
	где */
	private ITexSubItemsElement getStatementProof(IPropertySource ps, Partition partition) throws Exception
	{
		String index = TexUtils.index(SpecialRowsInitializer.getRowNumber(ps, partition));
		BigInteger z = AlternatingCharTableUtil.calcZX(partition);

		StringBuffer buffer = new StringBuffer();
		int count = 0;
		for (Pair<Integer, Integer> pair : NumberUtilities.factorization(z))
		{
			buffer = (count > 0 && count % 3 == 0) ? buffer.append("\\\\ \n") : buffer;
			buffer.append(getExp(pair)).append(",");
			count++;
		}

		UnionTexElement union = UnionTexElement.union();
		union.addSubElement(StringTexElement.text(
			"Так как $z" + index + " = " + z + " = " + TexUtils.getFactorization(z) + "$, то по\n" +
			"лемме 3 из \\cite{Aleev} $l" + index + "$ --- наименьшее общее кратное чисел\n" +
			//"\\[\n" + buffer + "\\]\n" +
			TexBeginEndElement.gather().setWithoutNumber().addSubElement(StringTexElement.text(buffer.toString())).generateContent() +
			"где "))
			.addSubElement(getIndexesElement(ps, partition)).addSubElement(StringTexElement.newLine())
			.addSubElement(getExponentsElement(ps, partition));
		return union;
	}

	private ITexSubItemsElement getProof(IPropertySource ps) throws Exception
	{
		ITexSubItemsElement proof = TexBeginEndElement.proof();
		for (Partition partition : SpecialRowsInitializer.listSpecialNotIntegerCharacterRows(ps))
		{
			proof.addSubElement(getStatementProof(ps, partition)).addSubElement(StringTexElement.newLineDouble());
		}
		return proof;
	}


	@Override
	protected ITexElement directRun(IPropertySource ps) throws Exception
	{
		ITexElement lemma = getLemma(ps);
		return UnionTexElement.union().addSubElement(lemma).addSubElement(getProof(ps));
	}

	@Override
	protected Class[] getDependentInitializers()
	{
		return DEPENDENCIES;
	}
}
